/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
// DataArray.cpp: implementation of the CDataArray class.
//
//////////////////////////////////////////////////////////////////////

#include "ssi_dataarray.h"
#include "ssi_dataarray.h"
#include "ssi_dataarray.h"

#include "ssi_internals.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


CDataArray::CDataArray()
{
	AccessCtr = 0;
  Type = SSI_NULL;
}

CDataArray::CDataArray(CDataArray& Other)
{
	// This is evidently never called
  AccessCtr = 1;
	Type = Other.Type;
  CopyArray(Other);
}

CDataArray::~CDataArray()
{
	SSI_INT64 num_elems = array.get_num_elements();
	SSI_INT64 ctr;
	CData* aData = SSI_NULL;
	for(ctr = 0; ctr < num_elems; ctr++){
		aData = array.remove_ptr(ctr);
		if(aData != SSI_NULL){
			//aData->DeleteData(aData);
			delete aData;
		}
	}
}

CDataArray& CDataArray::operator =(CDataArray &Other)
{
  AccessCtr = 1;
	Type = Other.Type;
  CopyArray(Other);
  
  return *this;
}


void CDataArray::CopyArray(CDataArray &In)
{
  SSI_INT64 num_elems = In.array.get_num_elements();
  SSI_INT64 ctr = 0;

  SSI_PTR** new_data = SSI_NULL;
  SSI_PTR** start = SSI_NULL;
  if(num_elems > 0)
  {
		// 1 SSI_DISPLAY_FILE_NEW
    new_data = new SSI_PTR*[num_elems];
    start = new_data;
  }
  SSI_PTR** in_data = (SSI_PTR**)In.array.get_array();
  CData* newData;
  CData* inData;

  for(ctr = 0; ctr < num_elems; ctr++)
	{
    inData = (CData*)((in_data++)[0]);
    if(inData){
      newData = CData::NewData(Type);
      if(!newData) return;
      *newData = *inData;
      new_data[ctr] = (SSI_PTR*)newData;
    }else{
			new_data[ctr] = SSI_NULL;  // Because not all ptrs contain data
    }
  }

  array.set_array_ptr(start);
  array.copy_dimensions(In.array);
}

CStatus CDataArray::AddData(const String& sData, DimNode Dim)
{
  CData* aData = 0;
  aData = CData::NewData(Type);
	
	if(!aData){
		return CStatus(sERROR, ERR01000);
	}

  if(!aData->DataFromString(sData))
  {
		// Should this or not be here?
    //return STAT_ERR;
  }
	
  return AddData(aData, Dim, 0);  
}

CStatus CDataArray::AddData(CData* aData, DimNode Dim, SSI_BOOL bDoClone)
{
  CData* Temp;
	SSI_BOOL bDelDim = 0;

  if(!Dim) 
  {
		bDelDim = 1;
    Dim = InitializeDimensions();    
  }

  if(bDoClone)
  {
    Temp = CData::NewData(Type);
		if(!Temp){
			if(bDelDim) delete Dim;
			return CStatus(sERROR, ERR01001);
		}
    *Temp = *aData;
		delete aData;
  }
  else
  {
    Temp = aData;
  }

	if(!Temp){
		if(bDelDim) delete Dim;
		return CStatus(sERROR, ERR01002);
	}
  if(!array.set_at(Dim, Temp))
  {
		if(bDelDim) delete Dim;
    return CStatus(sERROR, ERR01003);;
  }
	if(bDelDim) delete Dim;
  return STAT_OK;
}


CData& CDataArray::GetData(DimNode Dim)
{
  CData* temp = array.get_at(Dim);

  if(!temp)
  {
    // Need to set against dimensions
    temp = CData::NewData(Type);
    array.set_at(Dim, temp);
  }
  return *temp;
}

CData* CDataArray::GetData(SSI_INT64 Ind)
{
	CData* temp = array.get_at(Ind);
  if(!temp)
  {
    // Need to set against dimensions
    // temp = CData::NewData(Type);
    // array.set_at(Dim, temp);
  }
  return temp;
}


DimNode CDataArray::InitializeDimensions()
{
  array.clear();
	// 1 SSI_DISPLAY_FILE_NEW
  DimNode DefaultDim = new DimensionT;
  DefaultDim->Dim = 1;
  DefaultDim->Next = SSI_NULL;
  return DefaultDim;
}

SSI_INT64 CDataArray::GetNumElems()
{
  return array.get_num_elements();
}

SSI_INT64 CDataArray::Increment()
{
  AccessCtr++;
  return AccessCtr;
}

SSI_INT64 CDataArray::Decrement()
{
  AccessCtr--;
  return AccessCtr;
}

SSI_INT64 CDataArray::GetAccessCtr()
{
  return AccessCtr;
}

CData* CDataArray::GetNextData(DimNode& Dim, SSI_BOOL &EOL, SSI_BOOL bReset, SSI_BOOL bIncludeNULLs)
{
	static DimNode Curr = SSI_NULL;
	static DimNode Orig = SSI_NULL;

	DimNode Temp = SSI_NULL;
	CData* Ret = SSI_NULL;

	EOL = 0;

	if(bReset && Curr){
		delete Orig;
		Orig = SSI_NULL;
		Curr = SSI_NULL;
	}
	
	while(!Ret){
			Temp = array.get_next_elem(Curr, 1);
			Dim = Curr;
			if(!Temp){
				EOL = 1;  // End of List Reached, but still may be good data... and need to keep the Dim
			}
			if(!Orig){
				Orig = Curr;  // should be a new node
			}
			
			//if(!Temp){
			//	EOL = 1;
			//}

			Ret = array.get_at(Curr);
			if(bIncludeNULLs || EOL){  // return regardless
				return Ret;
			}
	}
	return Ret;
}

DimNode CDataArray::GetDims(void)
{
	return array.get_dims();
}




